上一篇最後講到...
「另外啟動一條執行序,然後不停檢查這個『synthesis.speaking』吧!」
什麼叫執行緒?這裡講的是讓外行人理解「技術領域有這個議題與技巧」與「這個議題與技巧為何被討論」而已,但實際上怎麼做、或有什麼魔鬼藏在裡頭....讓AI來幫忙煩惱吧!
執行緒的英文稱為「Thread」,中文可以寫執行緒、執行序、線程,都是指這件事。
它的功能在於:「多核心電腦」一次可以執行很多軟體、一個軟體可以執行很多功能....但是可以在「多核心電腦」上執行的軟體要如何在「單核心電腦」上正常運作呢?(記得有個東西叫Java嗎?)這就是執行序!從軟體層面去模擬多個核心、將「事情」做排程後排隊依序執行。
講白話一點,「把這件事情丟到背景去執行」這樣的事情就是靠「執行序」做出來的。
不同程式語言設計執行序的方式都不太一樣,甚至還有多種設計執行序的方法。
在Flutter上,剛好就是這種情況。(唉...我想念Java。)
好!問問AI!(這次做的功能有點心血來潮、改動幅度有點大!準備好了!)
「請依序以_listData中的InputData爲資料執行_speak功能,另外開啟執行序,會檢查_listData是否還有資料等著被執行,和_speak是否仍在播放語音,當兩項都為否,則關閉錄音。」
結果...(一次就完成,而且可以無閃退的執行,雖然功能尚未完成。)
  final WebRecorder _recorder = WebRecorder();
  html.SpeechSynthesis? _synthesis;
  html.SpeechSynthesisUtterance? _utterance;
  Queue<InputData> _queue = Queue<InputData>();
  TtsRecorder() {
    _synthesis = html.window.speechSynthesis;
    _utterance = html.SpeechSynthesisUtterance();
  }
  Future<void> speakAndRecord(List<InputData> inputDataList) async {
    if (inputDataList.isEmpty) {
      return;
    }
    // Add all InputData objects to the queue
    _queue.addAll(inputDataList);
    // Start recording
    await _recorder.startRecording();
    // Process the queue
    processQueue();
  }
  void processQueue() {
    if (_queue.isNotEmpty) {
      var inputData = _queue.removeFirst();
      if (inputData.value is String) {
        // Speak the text
        _utterance!.text = inputData.value;
        _synthesis!.speak(_utterance!);
        checkSpeaking();
      }
    }
  }
  Future<void> checkSpeaking() async {
    await Future.delayed(Duration(milliseconds: 1000));
    if (_synthesis?.speaking??false) {
      // If _synthesis is still speaking, wait for a short delay and then check again
      checkSpeaking();
    } else if (_queue.isNotEmpty) {
      // If _synthesis is not speaking but there are still InputData objects in the queue, process the queue
      processQueue();
    } else {
      // If _synthesis is not speaking and the queue is empty, stop recording
      _recorder.stopRecording();
    }
  }
(為什麼未完成?下一篇解釋啦!)